//----------- BaseScene 必须放到 场景的一级节点下 -----------

using System;
using System.Collections;
using System.Collections.Generic;
using SCore.Util;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;

namespace Function.SAsset
{
    public partial class XSceneManager
    {
        public enum OpMode
        {
            Load = 1,
            UnLoad = 2,
        }

        // 场景任务
        public class SceneTask
        {
            //task
            public float _progress; //进度
            public string _sceneName; //场景名
            internal OpMode _opMode; //任务类型
            internal LoadSceneMode _loadSceneMode; //加载模式
            internal Action<SceneTask> _callback; //加载完成回调
            internal SceneInstance _instance;
            internal bool _destroy = false; //删除

            //run
            public Camera _camera; //相机
            public List<Light> _lights = new List<Light>(); //灯光
            public Volume _volume; //后处理
            public BaseScene _baseScene; //BaseScene逻辑
            public int _layer = LayerMask.NameToLayer("Default");


            /// <summary>
            /// 查找BaseScene
            /// </summary>
            /// <returns>BaseScene</returns>
            private BaseScene FindBaseScene()
            {
                if (IsVailAndLoadFinish())
                {
                    var rootObjs = _instance.Scene.GetRootGameObjects();
                    BaseScene baseScene = Array
                        .Find(rootObjs, (obj) => { return obj.GetComponent<BaseScene>() != null; })
                        ?.GetComponent<BaseScene>();
                    return baseScene;
                }

                return null;
            }

            /// <summary>
            /// 是否是单场景
            /// </summary>
            /// <returns></returns>
            public bool IsSingle()
            {
                return _loadSceneMode == LoadSceneMode.Single;
            }

            /// <summary>
            /// 场景有效并且是否加载完成
            /// </summary>
            /// <returns></returns>
            public bool IsVailAndLoadFinish()
            {
                var scene = GetScene();
                return scene.IsValid() && scene.isLoaded;
            }

            /// <summary>
            /// 得到场景
            /// </summary>
            /// <returns></returns>
            public Scene GetScene()
            {
                return _instance.Scene;
            }

            /// <summary>
            /// 卸载场景
            /// </summary>
            public void UnLoad()
            {
                if (IsVailAndLoadFinish())
                {
                    _opMode = OpMode.UnLoad;
                    Instance._sceneTaskQueue.Enqueue(this);
                }
                else
                {
                    _destroy = true;
                }
            }

            /// <summary>
            /// 绑定场景数据
            /// </summary>
            public void Bind()
            {
                var scene = GetScene();
                var objs = scene.GetRootGameObjects();
                if (IsSingle())
                {
                    _baseScene = FindBaseScene();
                }

                if (_camera == null)
                {
                    foreach (var obj in objs)
                    {
                        int cullingMask = 1 << _layer;
                        ProcessAll(obj.transform, cullingMask, _layer);
                        obj.transform.ExecuteAllType1((tran) =>
                        {
                            //灯光的处理
                            ProcessAll(tran, cullingMask, _layer);
                        }, AlwaysTrue);
                    }

                    bool AlwaysTrue(Transform tran) => true;

                    void ProcessCamera(Transform tran, int cullingMask)
                    {
                        if (tran.name == "Main Camera")
                        {
                            _camera = tran.GetComponent<Camera>();
                            var cameraData = _camera.GetComponent<UniversalAdditionalCameraData>();
                            cameraData.volumeLayerMask = cullingMask;
                            _camera.cullingMask = cullingMask;
                            if (cameraData.cameraStack != null)
                            {
                                cameraData.cameraStack.Clear();
                            }

                            // if (UIManager.HasInstance())
                            // {
                            //     if (cameraData.cameraStack != null &&
                            //         !cameraData.cameraStack.Contains(UIManager.Instance.UICamera))
                            //         cameraData.cameraStack.Add(UIManager.Instance.UICamera);
                            // }

                            _camera.enabled = true;
                        }
                    }

                    void ProcessLight(Transform tran, int cullingMask)
                    {
                        var light = tran.GetComponent<Light>();
                        if (light != null)
                        {
                            _lights.Add(light);
                            light.cullingMask = cullingMask;
                            light.enabled = true;
                        }
                    }

                    void ProcessVolume(Transform tran, int layer)
                    {
                        if (tran.name == "Global Volume")
                        {
                            var volume = tran.GetComponent<Volume>();
                            _volume = volume;
                            _volume.weight = 1;
                            _volume.gameObject.layer = layer;
                        }
                    }

                    void ProcessAll(Transform tran, int cullingMask, int layer)
                    {
                        ProcessLight(tran, cullingMask);
                        //相机的处理
                        ProcessCamera(tran, cullingMask);
                        //后处理的处理
                        ProcessVolume(tran, _layer);
                    }
                }
                else
                {
                    if (_camera != null)
                    {
                        _camera.enabled = true;
                    }

                    foreach (var light in _lights)
                    {
                        light.enabled = true;
                    }

                    if (_volume != null)
                    {
                        _volume.weight = 1;
                    }
                }
            }

            /// <summary>
            /// 卸载场景数据
            /// </summary>
            public void UnBind()
            {
                if (_camera != null)
                {
                    _camera.enabled = false;
                }

                foreach (var light in _lights)
                {
                    light.enabled = false;
                }

                if (_volume != null)
                {
                    _volume.weight = 0;
                }
            }

            /// <summary>
            /// 设置加载场景的层级
            /// </summary>
            public void SetSceneLayer(string layer)
            {
                _layer = LayerMask.NameToLayer(layer);
            }
        }

        //任务主函数
        private Coroutine _main;

        //场景任务队列
        private readonly Queue<SceneTask> _sceneTaskQueue = new Queue<SceneTask>();

        //场景Stack --- 场景地图
        private readonly Stack<SceneTask> _sceneStack = new Stack<SceneTask>();

        /// <summary>
        /// 查找Single场景
        /// </summary>
        private SceneTask FindSingleSceneTask()
        {
            foreach (var sceneTask in _sceneStack)
            {
                if (sceneTask.IsSingle())
                {
                    return sceneTask;
                }
            }

            return null;
        }

        private SceneTask FindSceneTaskByName(string sceneName)
        {
            foreach (var sceneTask in _sceneTaskQueue)
            {
                if (sceneTask._sceneName == sceneName)
                {
                    return sceneTask;
                }
            }

            return null;
        }

        /// <summary>
        /// 弹出指定item
        /// </summary>
        /// <param name="sceneTask"></param>
        private void PopStack(SceneTask sceneTask)
        {
            Stack<SceneTask> tempStack = new Stack<SceneTask>();
            while (_sceneStack.Count > 0)
            {
                var currentNode = _sceneStack.Pop();

                if (currentNode != sceneTask)
                {
                    tempStack.Push(currentNode);
                }
            }

            while (tempStack.Count > 0)
            {
                _sceneStack.Push(tempStack.Pop());
            }
        }


        private SceneTask GetSecondFirstStack()
        {
            var firstItem = _sceneStack.Pop();
            var secondItem = _sceneStack.Peek();
            _sceneStack.Push(firstItem);
            return secondItem;
        }

        /// <summary>
        /// 启动场景任务
        /// </summary>
        public override void Init()
        {
            if (_main == null)
            {
                _main = CoRoutineExecutors.Run(TickSceneTask());
            }
        }

        public override void Clear()
        {
            _mainScene = null;
            _sceneTaskQueue.Clear();
            _sceneStack.Clear();
            if (_main != null)
            {
                CoRoutineExecutors.Stop(_main);
                _main = null;
            }
        }

        /// <summary>
        /// 加入任务
        /// </summary>
        private SceneTask AddTask(string sceneName, Action<SceneTask> doneCallback = null,
            LoadSceneMode loadSceneMode = LoadSceneMode.Single, OpMode opMode = OpMode.Load,
            SceneInstance instance = default)
        {
            SceneTask sceneTask = new SceneTask()
            {
                _opMode = opMode,
                _sceneName = sceneName,
                _loadSceneMode = loadSceneMode,
                _callback = doneCallback,
                _instance = instance
            };
            ($"[scene] add Task {sceneTask}").Log();
            _sceneTaskQueue.Enqueue(sceneTask);
            return sceneTask;
        }

        /// <summary>
        /// 加入任务
        /// </summary>
        private SceneTask AddTask<T>(Action<SceneTask> doneCallback = null,
            LoadSceneMode loadSceneMode = LoadSceneMode.Single, OpMode opMode = OpMode.Load,
            SceneInstance instance = default)
            where T : BaseScene
        {
            var sceneName = typeof(T).Name;
            return AddTask($"{sceneName}.unity", doneCallback, loadSceneMode, opMode, instance);
        }


        /// <summary>
        /// tick 任务
        /// </summary>
        private IEnumerator TickSceneTask()
        {
            while (true)
            {
                if (_sceneTaskQueue.Count > 0)
                {
                    var sceneTask = _sceneTaskQueue.Dequeue();
                    if (sceneTask._opMode == OpMode.Load)
                    {
                        ($"[scene] start load scene: {sceneTask._sceneName}").Log();
                        //AOTEventManager.BroadCast(AOTEventType.XSceneManager_ChangeScene, sceneTask);
                        if (sceneTask._loadSceneMode == LoadSceneMode.Single)
                        {
                            yield return SingleLoadTask(sceneTask);
                        }
                        else if (sceneTask._loadSceneMode == LoadSceneMode.Additive)
                        {
                            yield return AdditiveLoadTask(sceneTask);
                        }
                    }

                    if (sceneTask._opMode == OpMode.UnLoad)
                    {
                        ($"[scene] start unload scene: {sceneTask._sceneName}").Log();
                        //AOTEventManager.BroadCast(AOTEventType.XSceneManager_UnLoad, sceneTask);
                        yield return UnLoadSceneTask(sceneTask);
                    }
                }

                yield return null;
                yield return null;
            }
        }

        private IEnumerator SingleLoadTask(SceneTask sceneTask)
        {
            var sceneName = sceneTask._sceneName;
            var singleScene = FindSingleSceneTask();
            if (singleScene != null)
            {
                if (singleScene._sceneName == sceneTask._sceneName)
                {
                    ($"[scene] already in {sceneName}").Error();
                    yield break;
                }

                singleScene._baseScene.OnBeforeUnload();
            }

            var asHandle = Addressables.LoadSceneAsync(sceneTask._sceneName, sceneTask._loadSceneMode);
            while (!asHandle.IsDone)
            {
                sceneTask._progress = asHandle.PercentComplete;
                yield return null;
            }

            ($"[scene] end load scene: {sceneName}").Log();
            //Bind
            sceneTask._instance = asHandle.Result;
            sceneTask.Bind();
            if (sceneTask._baseScene == null)
            {
                ($"[scene] baseScene {sceneName} not found").Error();
                yield break;
            }

            //stack处理
            _sceneStack.Clear();
            _sceneStack.Push(sceneTask);

            sceneTask._baseScene.OnAfterLoaded();
            if (_mainScene != null)
            {
                _lastSceneName = _mainScene._sceneName;
            }

            _mainScene = sceneTask;
            sceneTask._callback?.Invoke(_mainScene);
        }

        private IEnumerator AdditiveLoadTask(SceneTask sceneTask)
        {
            var sceneName = sceneTask._sceneName;
            var asHandle = Addressables.LoadSceneAsync(sceneName, sceneTask._loadSceneMode);
            while (!asHandle.IsDone)
            {
                sceneTask._progress = asHandle.PercentComplete;
                yield return null;
            }

            ($"[scene] end load scene: {sceneName}").Log();
            //Bind
            sceneTask._instance = asHandle.Result;
            _mainScene.UnBind();
            sceneTask.Bind();
            //stack处理
            _sceneStack.Push(sceneTask);

            SceneManager.SetActiveScene(asHandle.Result.Scene);
            _lastSceneName = _mainScene._sceneName;
            _mainScene = sceneTask;
            sceneTask._callback?.Invoke(_mainScene);

            if (sceneTask._destroy)
            {
                sceneTask.UnLoad();
            }
        }

        private IEnumerator UnLoadSceneTask(SceneTask sceneTask)
        {
            var sceneName = sceneTask._sceneName;
            if (!sceneTask.IsVailAndLoadFinish())
            {
                yield break;
            }

            //如果卸载的是当前场景
            if (sceneTask == MainScene)
            {
                _sceneStack.Pop(); // 弹出顶场景
                _mainScene = _sceneStack.Peek(); // 重新设置主场景
                _lastSceneName = sceneTask._sceneName;
            }
            else
            {
                PopStack(sceneTask);
            }

            var asHandle = Addressables.UnloadSceneAsync(sceneTask._instance);
            while (!asHandle.IsDone)
            {
                sceneTask._progress = asHandle.PercentComplete;
                yield return null;
            }

            _mainScene.Bind();
            ($"[scene] end unload scene: {sceneName}").Log();
            sceneTask._callback?.Invoke(sceneTask);
        }
    }
}